using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;

namespace Dapper_Core.Common
{
    public class XmlUtility
    {
        #region 字段定义
        /// <summary>
        /// XML文件的物理路径
        /// </summary>
        private string _filePath = string.Empty;
        /// <summary>
        /// XML文件的内容
        /// </summary>
        private string _xmlString = string.Empty;
        /// <summary>
        /// Xml文档
        /// </summary>
        private XmlDocument _xml;
        /// <summary>
        /// XML的根节点
        /// </summary>
        private XmlElement _element;
        #endregion

        /// <summary>
        /// 实例化XmlUtility对象
        /// </summary>
        /// <param name="xmlFilePath">Xml文件的相对路径</param>
        public XmlUtility(string xmlFilePath, string xmlString = "")
        {
            //获取XML文件的绝对路径
            _filePath = xmlFilePath;
            _xmlString = xmlString;
            InitRootElement();
        }

        /// <summary>
        /// 初始化XML的根节点
        /// </summary>
        private void InitRootElement()
        {
            _xml = new XmlDocument();

            if (File.Exists(_filePath))
            {
                _xml.Load(this._filePath);//加载XML文件
            }
            else
            {
                _xml.LoadXml(this._xmlString);//加载XML文件
            }

            //为XML的根节点赋值
            _element = _xml.DocumentElement;
        }

        #region 获取指定XPath表达式的第一个节点对象
        /// <summary>
        /// 获取指定XPath表达式的第一个节点对象
        /// </summary>        
        /// <param name="xPath">XPath表达式,
        /// 范例1: @"/Skill/First/SkillItem", 等效于 @"//Skill/First/SkillItem"
        /// 范例2: @"/Table[USERNAME='a']" , []表示筛选,USERNAME是Table下的一个子节点.
        /// 范例3: @"/ApplyPost/Item[@itemName='岗位编号']",@itemName是Item节点的属性.
        /// </param>
        public XmlNode GetFirstNode(string xPath)
        {
            //返回XPath节点
            return _element.SelectSingleNode(xPath);
        }

        /// <summary>
        /// 获取指定XPath表达式第一个节点的值
        /// </summary>        
        /// <param name="xPath">XPath表达式,
        /// 范例1: @"/Skill/First/SkillItem", 等效于 @"//Skill/First/SkillItem"
        /// 范例2: @"/Table[USERNAME='a']" , []表示筛选,USERNAME是Table下的一个子节点.
        /// 范例3: @"/ApplyPost/Item[@itemName='岗位编号']",@itemName是Item节点的属性.
        /// </param>
        public string GetFirstNodeValue(string xPath)
        {
            if (string.IsNullOrEmpty(xPath)) return null;
            //返回XPath节点
            return GetFirstNode(xPath)?.InnerText;
        }

        /// <summary>
        /// 获取指定XPath表达式第一个节点的属性值
        /// </summary>        
        /// <param name="xPath">XPath表达式,
        /// 范例1: @"/Skill/First/SkillItem", 等效于 @"//Skill/First/SkillItem"
        /// 范例2: @"/Table[USERNAME='a']" , []表示筛选,USERNAME是Table下的一个子节点.
        /// 范例3: @"/ApplyPost/Item[@itemName='岗位编号']",@itemName是Item节点的属性.
        /// </param>
        /// <param name="attributeName">属性名</param>
        public string GetFirstNodeAttribute(string xPath, string attributeName)
        {
            if (string.IsNullOrEmpty(xPath)) return null;
            //返回XPath节点
            XmlAttribute attribute = GetFirstNode(xPath)?.Attributes[attributeName];
            return attribute == null ? null : attribute.Value;
        }
        #endregion

        #region 获取指定XPath表达式的第n个节点对象
        /// <summary>
        /// 获取指定XPath表达式的第n个节点对象
        /// </summary>
        /// <param name="xPath">XPath表达式,
        /// 范例1: @"/Skill/First/SkillItem", 等效于 @"//Skill/First/SkillItem"
        /// 范例2: @"/Table[USERNAME='a']" , []表示筛选,USERNAME是Table下的一个子节点
        /// 范例3: @"/ApplyPost/Item[@itemName='岗位编号']",@itemName是Item节点的属性
        /// </param>
        /// <param name="index">索引从0开始</param>
        /// <returns></returns>
        public XmlNode GetSingleNode(string xPath, int index)
        {
            //返回XPath节点
            return GetNodes(xPath).Item(index);
        }

        /// <summary>
        /// 获取指定XPath表达式第n个节点的值
        /// </summary>        
        /// <param name="xPath">XPath表达式,
        /// 范例1: @"/Skill/First/SkillItem", 等效于 @"//Skill/First/SkillItem"
        /// 范例2: @"/Table[USERNAME='a']" , []表示筛选,USERNAME是Table下的一个子节点.
        /// 范例3: @"/ApplyPost/Item[@itemName='岗位编号']",@itemName是Item节点的属性.
        /// </param>
        /// <param name="index">索引从0开始</param>
        public string GetSingleNodeValue(string xPath, int index)
        {
            if (string.IsNullOrEmpty(xPath)) return null;
            //返回XPath节点
            return GetSingleNode(xPath, index)?.InnerText;
        }

        /// <summary>
        /// 获取指定XPath表达式第n个节点的属性值
        /// </summary>        
        /// <param name="xPath">XPath表达式,
        /// 范例1: @"/Skill/First/SkillItem", 等效于 @"//Skill/First/SkillItem"
        /// 范例2: @"/Table[USERNAME='a']" , []表示筛选,USERNAME是Table下的一个子节点.
        /// 范例3: @"/ApplyPost/Item[@itemName='岗位编号']",@itemName是Item节点的属性.
        /// </param>
        /// <param name="index">索引从0开始</param>
        /// <param name="attributeName">属性名</param>
        public string GetSingleNodeAttribute(string xPath, int index, string attributeName)
        {
            if (string.IsNullOrEmpty(xPath)) return null;
            //返回XPath节点
            XmlAttribute attribute = GetSingleNode(xPath, index)?.Attributes[attributeName];
            return attribute == null ? null : attribute.Value;
        }
        #endregion

        public string GetValueByTagName(XmlElement element, string tagName, int tagIndex = 0)
        {
            if (element == null || string.IsNullOrEmpty(tagName)) return null;
            XmlNodeList nodeList = element.GetElementsByTagName(tagName);
            string result = nodeList.Item(tagIndex)?.InnerText;
            return result;
        }

        public string GetAttributeByTagName(XmlElement element, string tagName, string attributeName, int tagIndex = 0)
        {
            if (element == null || string.IsNullOrEmpty(tagName) || string.IsNullOrEmpty(attributeName)) return null;
            XmlNodeList nodeList = element.GetElementsByTagName(tagName);
            XmlAttribute attribute = nodeList.Item(tagIndex)?.Attributes[attributeName];
            return attribute == null ? null : attribute.Value;
        }

        /// <summary>
        /// 获取指定XPath表达式的节点对象列表
        /// </summary>
        /// <param name="xPath">XPath表达式,
        /// 范例1: @"/Skill/First/SkillItem", 等效于 @"//Skill/First/SkillItem"
        /// 范例2: @"/Table[USERNAME='a']" , []表示筛选,USERNAME是Table下的一个子节点
        /// 范例3: @"/ApplyPost/Item[@itemName='岗位编号']",@itemName是Item节点的属性
        /// </param>
        /// <returns></returns>
        public XmlNodeList GetNodes(string xPath)
        {
            //返回XPath节点
            return _element.SelectNodes(xPath);
        }

        #region 静态方法

        #region 创建根节点对象
        /// <summary>
        /// 创建根节点对象
        /// </summary>
        /// <param name="xmlFilePath">Xml文件的相对路径</param>        
        private static XmlElement CreateRootElement(string xmlFilePath)
        {
            //定义变量，表示XML文件的绝对路径
            string filePath = "";

            //获取XML文件的绝对路径
            //filePath = System.Web.HttpContext.Current.Server.MapPath(xmlFilePath);
            filePath = xmlFilePath;

            //创建XmlDocument对象
            XmlDocument xmlDocument = new XmlDocument();
            //加载XML文件
            xmlDocument.Load(filePath);

            //返回根节点
            return xmlDocument.DocumentElement;
        }
        #endregion

        #region 获取指定XPath表达式节点的值
        /// <summary>
        /// 获取指定XPath表达式节点的值
        /// </summary>
        /// <param name="xmlFilePath">Xml文件的相对路径</param>
        /// <param name="xPath">XPath表达式,
        /// 范例1: @"Skill/First/SkillItem", 等效于 @"//Skill/First/SkillItem"
        /// 范例2: @"Table[USERNAME='a']" , []表示筛选,USERNAME是Table下的一个子节点.
        /// 范例3: @"ApplyPost/Item[@itemName='岗位编号']",@itemName是Item节点的属性.
        /// </param>
        public static string GetValue(string xmlFilePath, string xPath)
        {
            //创建根对象
            XmlElement rootElement = CreateRootElement(xmlFilePath);

            //返回XPath节点的值
            return rootElement.SelectSingleNode(xPath)?.InnerText;
        }
        #endregion

        #region 获取指定XPath表达式节点的属性值
        /// <summary>
        /// 获取指定XPath表达式节点的属性值
        /// </summary>
        /// <param name="xmlFilePath">Xml文件的相对路径</param>
        /// <param name="xPath">XPath表达式,
        /// 范例1: @"Skill/First/SkillItem", 等效于 @"//Skill/First/SkillItem"
        /// 范例2: @"Table[USERNAME='a']" , []表示筛选,USERNAME是Table下的一个子节点.
        /// 范例3: @"ApplyPost/Item[@itemName='岗位编号']",@itemName是Item节点的属性.
        /// </param>
        /// <param name="attributeName">属性名</param>
        public static string GetAttributeValue(string xmlFilePath, string xPath, string attributeName)
        {
            //创建根对象
            XmlElement rootElement = CreateRootElement(xmlFilePath);

            //返回XPath节点的属性值
            XmlAttribute attribute = rootElement.SelectSingleNode(xPath)?.Attributes[attributeName];
            return attribute == null ? null : attribute.Value;
        }
        #endregion

        #endregion
    }
}
